package com.gitee.wsl.net.syncsocket

import com.gitee.wsl.jvm.net.asyncsocket.SocksCoroutineSocket
import com.gitee.wsl.jvm.net.asyncsocket.SocksException
import kotlinx.coroutines.runBlocking
import org.junit.Assert.assertThrows

import java.net.InetSocketAddress
import java.nio.channels.AsynchronousSocketChannel
import kotlin.test.BeforeTest
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertTrue

class SocksTest {

    lateinit var channel: AsynchronousSocketChannel

    @BeforeTest
    fun initChannel() {
        channel = AsynchronousSocketChannel.open()
    }

    @Test
    fun testNoAuth(): Unit = runBlocking {
        val socket = SocksCoroutineSocket(InetSocketAddress("localhost", 1081), channel)
        socket.init()
        socket.connect(InetSocketAddress("example.com", 80))

        assertTrue(socket.isOpened)
        assertTrue(socket.isConnected)

        assertEquals(SocksCoroutineSocket.Method.NO_AUTH, socket.method)

        socket.close()
    }

    @Test
    fun testUserPassAuthCorrect(): Unit = runBlocking {
        val credentials = "username" to "password"
        val socket = SocksCoroutineSocket(InetSocketAddress("localhost", 1080), channel, credentials)
        socket.init()
        socket.connect(InetSocketAddress("example.com", 80))

        assertTrue(socket.isOpened)
        assertTrue(socket.isConnected)

        assertEquals(SocksCoroutineSocket.Method.USER_PASS, socket.method)

        socket.close()
    }

    @Test
    fun testUserPassAuthIncorrect(): Unit = runBlocking {
        val credentials = "username" to "blah"
        val socket = SocksCoroutineSocket(InetSocketAddress("localhost", 1080), channel, credentials)
        assertThrows(SocksException::class.java) {
            runBlocking { socket.init() }
        }
    }

    @Test
    fun testUserPassAuthWithoutCredentials(): Unit = runBlocking {
        val socket = SocksCoroutineSocket(InetSocketAddress("localhost", 1080), channel)
        socket.init()
        socket.connect(InetSocketAddress("example.com", 80))

        assertTrue(socket.isOpened)
        assertTrue(socket.isConnected)

        assertEquals(SocksCoroutineSocket.Method.NO_AUTH, socket.method)

        socket.close()
    }

    @Test
    fun testCredentialsWithNoAuthServer(): Unit = runBlocking {
        val credentials = "username" to "blah"
        val socket = SocksCoroutineSocket(InetSocketAddress("localhost", 1081), channel, credentials)
        socket.init()
        socket.connect(InetSocketAddress("example.com", 80))

        assertTrue(socket.isOpened)
        assertTrue(socket.isConnected)

        assertEquals(SocksCoroutineSocket.Method.NO_AUTH, socket.method)

        socket.close()
    }
}